home *** CD-ROM | disk | FTP | other *** search
/ Java Programmer's Toolkit / Java Programmer's Toolkit.iso / applets / spread~1 / spread~1 / spread~1.jav < prev    next >
Encoding:
Text File  |  1995-10-31  |  20.0 KB  |  849 lines

  1. /*
  2.  * @(#)SpreadSheet.java    1.17 95/03/09 Sami Shaio
  3.  *
  4.  * Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL purposes and without
  8.  * fee is hereby granted provided that this copyright notice
  9.  * appears in all copies. Please refer to the file "copyright.html"
  10.  * for further important copyright and licensing information.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  13.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  14.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  15.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  16.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  17.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  18.  */
  19. import java.applet.Applet;
  20. import java.awt.*;
  21. import java.io.*;
  22. import java.lang.*;
  23. import java.net.*;
  24.  
  25. public class SpreadSheet extends Applet {
  26.     String        title;
  27.     Font        titleFont;
  28.     Color        cellColor;
  29.     Color        inputColor;
  30.     int            cellWidth = 100;
  31.     int            cellHeight = 15;
  32.     int            titleHeight = 15;
  33.     int            rowLabelWidth = 15;
  34.     Font        inputFont;
  35.     boolean        isStopped = false;
  36.     boolean        fullUpdate = true;
  37.     int            rows;
  38.     int            columns;
  39.     int            currentKey = -1;
  40.     int            selectedRow = -1;
  41.     int            selectedColumn = -1;
  42.     SpreadSheetInput    inputArea;
  43.     Cell        cells[][];
  44.     Cell        current = null;
  45.  
  46.     public synchronized void init() {
  47.     String rs;
  48.     
  49.     cellColor = Color.white;
  50.     inputColor = new Color(100, 100, 225);
  51.     inputFont = new Font("Courier", Font.PLAIN, 10);
  52.     titleFont = new Font("Courier", Font.BOLD, 12);
  53.     title = getParameter("title");
  54.     if (title == null) {
  55.         title = "Spreadsheet";
  56.     }
  57.     rs = getParameter("rows");
  58.     if (rs == null) {
  59.         rows = 9;
  60.     } else {
  61.         rows = Integer.parseInt(rs);
  62.     }
  63.     rs = getParameter("columns");
  64.     if (rs == null) {
  65.         columns = 5;
  66.     } else {
  67.         columns = Integer.parseInt(rs);
  68.     }
  69.     cells = new Cell[rows][columns];
  70.     char l[] = new char[1];
  71.     for (int i=0; i < rows; i++) {
  72.         for (int j=0; j < columns; j++) {
  73.  
  74.         cells[i][j] = new Cell(this,
  75.                        Color.lightGray,
  76.                        Color.black,
  77.                        cellColor,
  78.                        cellWidth - 2,
  79.                        cellHeight - 2);
  80.         l[0] = (char)((int)'a' + j);
  81.         rs = getParameter("" + new String(l) + (i+1));
  82.         if (rs != null) {
  83.             cells[i][j].setUnparsedValue(rs);
  84.         }
  85.         }
  86.     }
  87.  
  88.     Dimension d = size();
  89.     inputArea = new SpreadSheetInput(null, this, d.width - 2, cellHeight - 1,
  90.                      inputColor, Color.white); 
  91.     resize(columns * cellWidth + rowLabelWidth,
  92.            ((rows + 1) * cellHeight) + cellHeight + titleHeight);
  93.     }
  94.  
  95.     public void setCurrentValue(float val) {
  96.     if (selectedRow == -1 || selectedColumn == -1) {
  97.         return;
  98.     }
  99.     cells[selectedRow][selectedColumn].setValue(val);
  100.     repaint();
  101.     }
  102.  
  103.     public void stop() {
  104.     isStopped = true;
  105.     }
  106.  
  107.     public void start() {
  108.     isStopped = false;
  109.     }
  110.  
  111.     public void destroy() {
  112.     for (int i=0; i < rows; i++) {
  113.         for (int j=0; j < columns; j++) {
  114.         if (cells[i][j].type == Cell.URL) {
  115.             cells[i][j].updaterThread.stop();
  116.         }
  117.         }
  118.     }
  119.     }
  120.  
  121.     public void setCurrentValue(int type, String val) {
  122.     if (selectedRow == -1 || selectedColumn == -1) {
  123.         return;
  124.     }
  125.     cells[selectedRow][selectedColumn].setValue(type, val);
  126.     repaint();
  127.     }
  128.  
  129.     public void update(Graphics g) {
  130.     if (! fullUpdate) {
  131.         int cx, cy;
  132.  
  133.         g.setFont(titleFont);
  134.         for (int i=0; i < rows; i++) {
  135.         for (int j=0; j < columns; j++) {
  136.             if (cells[i][j].needRedisplay) {
  137.             cx = (j * cellWidth) + 2 + rowLabelWidth;
  138.             cy = ((i+1) * cellHeight) + 2 + titleHeight;
  139.             cells[i][j].paint(g, cx, cy);
  140.             }
  141.         }
  142.         }
  143.     } else {
  144.         paint(g);
  145.         fullUpdate = false;
  146.     }
  147.     }
  148.  
  149.     public void recalculate() {
  150.     int    i,j;
  151.  
  152.     //System.out.println("SpreadSheet.recalculate");
  153.     for (i=0; i < rows; i++) {
  154.         for (j=0; j < columns; j++) {
  155.         if (cells[i][j] != null && cells[i][j].type == Cell.FORMULA) {
  156.             cells[i][j].setRawValue(evaluateFormula(cells[i][j].parseRoot));
  157.             cells[i][j].needRedisplay = true;
  158.         }
  159.         }
  160.     }
  161.     repaint();
  162.     }
  163.  
  164.     public float evaluateFormula(Node n) {
  165.     float    val = 0.0f;
  166.  
  167.     //System.out.println("evaluateFormula:");
  168.     //n.print(3);
  169.     if (n == null) {
  170.         //System.out.println("Null node");
  171.         return val;
  172.     }
  173.     switch (n.type) {
  174.       case Node.OP:
  175.         val = evaluateFormula(n.left);
  176.         switch (n.op) {
  177.           case '+':
  178.         val += evaluateFormula(n.right);
  179.         break;
  180.           case '*':
  181.         val *= evaluateFormula(n.right);
  182.         break;
  183.           case '-':
  184.         val -= evaluateFormula(n.right);
  185.         break;
  186.           case '/':
  187.         val /= evaluateFormula(n.right);
  188.         break;
  189.         }
  190.         break;
  191.       case Node.VALUE:
  192.         //System.out.println("=>" + n.value);
  193.         return n.value;
  194.       case Node.CELL:
  195.         if (n == null) {
  196.         //System.out.println("NULL at 192");
  197.         } else {
  198.         if (cells[n.row][n.column] == null) {
  199.             //System.out.println("NULL at 193");
  200.         } else {
  201.             //System.out.println("=>" + cells[n.row][n.column].value);
  202.             return cells[n.row][n.column].value;
  203.         }
  204.         }
  205.     }
  206.  
  207.     //System.out.println("=>" + val);
  208.     return val;
  209.     }    
  210.  
  211.     public synchronized void paint(Graphics g) {
  212.     int i, j;
  213.     int cx, cy;
  214.     char l[] = new char[1];
  215.  
  216.  
  217.     Dimension d = size();
  218.     g.setFont(titleFont);
  219.     i = g.getFontMetrics().stringWidth(title);
  220.     g.drawString((title == null) ? "Spreadsheet" : title,
  221.              (d.width - i) / 2, 12);
  222.     g.setColor(inputColor);
  223.     g.fillRect(0, cellHeight, d.width, cellHeight);
  224.     g.setFont(titleFont);
  225.     for (i=0; i < rows+1; i++) {
  226.         cy = (i+2) * cellHeight;
  227.         g.setColor(getBackground());
  228.         g.draw3DRect(0, cy, d.width, 2, true);
  229.         if (i < rows) {
  230.         g.setColor(Color.red);
  231.         g.drawString("" + (i+1), 2, cy + 12);
  232.         }
  233.     }
  234.     g.setColor(Color.red);
  235.     for (i=0; i < columns; i++) {
  236.         cx = i * cellWidth;
  237.         g.setColor(getBackground());
  238.         g.draw3DRect(cx + rowLabelWidth,
  239.               2 * cellHeight, 1, d.height, true);
  240.         if (i < columns) {
  241.         g.setColor(Color.red);
  242.         l[0] = (char)((int)'A' + i);
  243.         g.drawString(new String(l),
  244.                  cx + rowLabelWidth + (cellWidth / 2),
  245.                  d.height - 3);
  246.         }
  247.     }
  248.  
  249.     
  250.     for (i=0; i < rows; i++) {
  251.         for (j=0; j < columns; j++) {
  252.         cx = (j * cellWidth) + 2 + rowLabelWidth;
  253.         cy = ((i+1) * cellHeight) + 2 + titleHeight;
  254.         if (cells[i][j] != null) {
  255.             cells[i][j].paint(g, cx, cy);
  256.         }
  257.         }
  258.     }
  259.  
  260.     g.setColor(getBackground());
  261.     g.draw3DRect(0, titleHeight,
  262.               d.width,
  263.               d.height - titleHeight,
  264.               false);
  265.     inputArea.paint(g, 1, titleHeight + 1);
  266.     }
  267.     public boolean mouseDown(Event evt, int x, int y) {
  268.     Cell cell;
  269.     if (y < (titleHeight + cellHeight)) {
  270.         selectedRow = -1;
  271.         if (y <= titleHeight && current != null) {
  272.         current.deselect();
  273.         current = null;
  274.         }
  275.         return true;
  276.     }
  277.     if (x < rowLabelWidth) {
  278.         selectedRow = -1;
  279.         if (current != null) {
  280.         current.deselect();
  281.         current = null;
  282.         }
  283.         return true;
  284.     }
  285.     selectedRow = ((y - cellHeight - titleHeight) / cellHeight);
  286.     selectedColumn = (x - rowLabelWidth) / cellWidth;
  287.     if (selectedRow > rows ||
  288.         selectedColumn >= columns) {
  289.         selectedRow = -1;
  290.         if (current != null) {
  291.         current.deselect();
  292.         current = null;
  293.         }
  294.     } else {
  295.         if (selectedRow >= rows) {
  296.         selectedRow = -1;
  297.         if (current != null) {
  298.             current.deselect();
  299.             current = null;
  300.         }
  301.         return true;
  302.         }
  303.         cell = cells[selectedRow][selectedColumn];
  304.         inputArea.setText(new String(cell.getPrintString()));
  305.         if (current != null) {
  306.         current.deselect();
  307.         }
  308.         current = cell;
  309.         current.select();
  310.         requestFocus();
  311.         fullUpdate = true;
  312.         repaint();
  313.     }
  314.     return true;
  315.     }
  316.     public boolean keyDown(Event evt, int key) {
  317.     fullUpdate=true;
  318.     inputArea.keyDown(key);
  319.     return true;
  320.     }
  321. }
  322.  
  323. class CellUpdater extends Thread {
  324.     Cell     target;
  325.     InputStream dataStream = null;
  326.     StreamTokenizer tokenStream;
  327.  
  328.     public CellUpdater(Cell c) {
  329.     super("cell updater");
  330.     target = c;
  331.     }
  332.  
  333.     public void run() {
  334.     try {
  335.         dataStream = new URL(target.app.getDocumentBase(),
  336.                  target.getValueString()).openStream();
  337.         tokenStream = new StreamTokenizer(dataStream);
  338.         tokenStream.eolIsSignificant(false);
  339.  
  340.         while (true) {
  341.         switch (tokenStream.nextToken()) {
  342.         case tokenStream.TT_EOF:
  343.             dataStream.close();
  344.             return;
  345.         default:
  346.             break;
  347.         case tokenStream.TT_NUMBER:
  348.             target.setTransientValue((float)tokenStream.nval);
  349.             if (! target.app.isStopped && ! target.paused) {
  350.             target.app.repaint();
  351.             }
  352.             break;
  353.         }
  354.         try {
  355.             Thread.sleep(2000);
  356.         } catch (InterruptedException e) {
  357.             break;
  358.         }
  359.         }
  360.     } catch (IOException e) {
  361.         return;
  362.     }
  363.     }
  364. }
  365.  
  366. class Cell {
  367.     public static final int VALUE = 0;
  368.     public static final int LABEL = 1;
  369.     public static final int URL   = 2;
  370.     public static final int FORMULA = 3;
  371.     
  372.     Node    parseRoot;
  373.     boolean    needRedisplay;
  374.     boolean selected = false;
  375.     boolean transientValue = false;
  376.     public int    type = Cell.VALUE;
  377.     String    valueString = "";
  378.     String    printString = "v";
  379.     float    value;
  380.     Color    bgColor;
  381.     Color    fgColor;
  382.     Color    highlightColor;
  383.     int        width;
  384.     int        height;
  385.     SpreadSheet app;
  386.     CellUpdater    updaterThread;
  387.     boolean    paused = false;
  388.  
  389.     public Cell(SpreadSheet app,
  390.         Color bgColor,
  391.         Color fgColor,
  392.         Color highlightColor,
  393.         int width,
  394.         int height) {
  395.     this.app = app;
  396.     this.bgColor = bgColor;
  397.     this.fgColor = fgColor;
  398.     this.highlightColor = highlightColor;
  399.     this.width = width;
  400.     this.height = height;
  401.     needRedisplay = true;
  402.     }
  403.         
  404.     public void setRawValue(float f) {
  405.     valueString = Float.toString(f);
  406.     value = f;
  407.     }
  408.     public void setValue(float f) {
  409.     setRawValue(f);
  410.     printString = "v" + valueString;
  411.     type = Cell.VALUE;
  412.     paused = false;
  413.     app.recalculate();
  414.     needRedisplay = true;
  415.     }
  416.  
  417.     public void setTransientValue(float f) {
  418.     transientValue = true;
  419.     value = f;
  420.     needRedisplay = true;
  421.     app.recalculate();
  422.     }
  423.  
  424.     public void setUnparsedValue(String s) {
  425.     switch (s.charAt(0)) {
  426.       case 'v':
  427.         setValue(Cell.VALUE, s.substring(1));
  428.         break;
  429.       case 'f':
  430.         setValue(Cell.FORMULA, s.substring(1));
  431.         break;
  432.       case 'l':
  433.         setValue(Cell.LABEL, s.substring(1));
  434.         break;
  435.       case 'u':
  436.         setValue(Cell.URL, s.substring(1));
  437.         break;
  438.     }
  439.     }
  440.  
  441.     /**
  442.      * Parse a spreadsheet formula. The syntax is defined as:
  443.      *
  444.      * formula -> value
  445.      * formula -> value op value
  446.      * value -> '(' formula ')'
  447.      * value -> cell
  448.      * value -> <number>
  449.      * op -> '+' | '*' | '/' | '-'
  450.      * cell -> <letter><number>
  451.      */
  452.     public String parseFormula(String formula, Node node) {
  453.     String subformula;
  454.     String restFormula;
  455.     float value;
  456.     int length = formula.length();
  457.     Node left;
  458.     Node right;
  459.     char op;
  460.  
  461.     if (formula == null) {
  462.         return null;
  463.     }
  464.     subformula = parseValue(formula, node);
  465.     //System.out.println("subformula = " + subformula);
  466.     if (subformula == null || subformula.length() == 0) {
  467.         //System.out.println("Parse succeeded");
  468.         return null;
  469.     }
  470.     if (subformula == formula) {
  471.         //System.out.println("Parse failed");
  472.         return formula;
  473.     }
  474.  
  475.     // parse an operator and then another value
  476.     switch (op = subformula.charAt(0)) {
  477.       case 0:
  478.         //System.out.println("Parse succeeded");
  479.         return null;
  480.       case ')':
  481.         //System.out.println("Returning subformula=" + subformula);
  482.         return subformula;
  483.       case '+':
  484.       case '*':
  485.       case '-':
  486.       case '/':
  487.         restFormula = subformula.substring(1);
  488.         subformula = parseValue(restFormula, right=new Node());
  489.         //System.out.println("subformula(2) = " + subformula);
  490.         if (subformula != restFormula) {
  491.         //System.out.println("Parse succeeded");
  492.         left = new Node(node);
  493.         node.left = left;
  494.         node.right = right;
  495.         node.op = op;
  496.         node.type = Node.OP;
  497.         //node.print(3);
  498.         return subformula;
  499.         } else {
  500.         //System.out.println("Parse failed");
  501.         return formula;
  502.         }
  503.       default:
  504.         //System.out.println("Parse failed (bad operator): " + subformula);
  505.         return formula;
  506.     }
  507.     }
  508.  
  509.     public String parseValue(String formula, Node node) {
  510.     char    c = formula.charAt(0);
  511.     String    subformula;
  512.     String    restFormula;
  513.     float    value;
  514.     int    row;
  515.     int    column;
  516.  
  517.     //System.out.println("parseValue: " + formula);
  518.     restFormula = formula;
  519.     if (c == '(') {
  520.         //System.out.println("parseValue(" + formula + ")");
  521.         restFormula = formula.substring(1);
  522.         subformula = parseFormula(restFormula, node);
  523.         //System.out.println("rest=(" + subformula + ")");
  524.         if (subformula == null ||
  525.         subformula.length() == restFormula.length()) {
  526.         //System.out.println("Failed");
  527.         return formula;
  528.         } else if (! (subformula.charAt(0) == ')')) {
  529.             //System.out.println("Failed (missing parentheses)");
  530.         return formula;
  531.         }
  532.         restFormula = subformula;
  533.     } else if (c >= '0' && c <= '9') {
  534.         int i;
  535.  
  536.         //System.out.println("formula=" + formula);
  537.         try {
  538.         value = Float.valueOf(formula).floatValue();
  539.         } catch (NumberFormatException e) {
  540.         //System.out.println("Failed (number format error)");
  541.         return formula;
  542.         }
  543.         for (i=0; i < formula.length(); i++) {
  544.         c = formula.charAt(i);
  545.         if ((c < '0' || c > '9') && c != '.') {
  546.             break;
  547.         }
  548.         }
  549.         node.type = Node.VALUE;
  550.         node.value = value;
  551.         //node.print(3);
  552.         restFormula = formula.substring(i);
  553.         //System.out.println("value= " + value + " i=" + i +
  554.         //               " rest = " + restFormula);
  555.         return restFormula;
  556.     } else if (c >= 'A' && c <= 'Z') {
  557.         int i;
  558.  
  559.         column = c - 'A';
  560.         restFormula = formula.substring(1);
  561.         row = Float.valueOf(restFormula).intValue();
  562.         //System.out.println("row = " + row + " column = " + column);
  563.         for (i=0; i < restFormula.length(); i++) {
  564.         c = restFormula.charAt(i);
  565.         if (c < '0' || c > '9') {
  566.             break;
  567.         }
  568.         }
  569.         node.row = row - 1;
  570.         node.column = column;
  571.         node.type = Node.CELL;
  572.         //node.print(3);
  573.         if (i == restFormula.length()) {
  574.         restFormula = null;
  575.         } else {
  576.         restFormula = restFormula.substring(i);
  577.         if (restFormula.charAt(0) == 0) {
  578.             return null;
  579.         }
  580.         }        
  581.     }
  582.  
  583.     return restFormula;
  584.     }
  585.  
  586.  
  587.     public void setValue(int type, String s) {
  588.     paused = false;
  589.     if (this.type == Cell.URL) {
  590.         updaterThread.stop();
  591.         updaterThread = null;
  592.     }
  593.  
  594.     valueString = new String(s);
  595.     this.type = type;
  596.     needRedisplay = true;
  597.     switch (type) {
  598.       case Cell.VALUE:
  599.         setValue(Float.valueOf(s).floatValue());
  600.         break;
  601.       case Cell.LABEL:
  602.         printString = "l" + valueString;
  603.         break;
  604.       case Cell.URL:
  605.         printString = "u" + valueString;
  606.         updaterThread = new CellUpdater(this);
  607.         updaterThread.start();
  608.         break;
  609.       case Cell.FORMULA:
  610.         parseFormula(valueString, parseRoot = new Node());
  611.         printString = "f" + valueString;
  612.         break;
  613.     }
  614.     app.recalculate();
  615.     }
  616.  
  617.     public String getValueString() {
  618.     return valueString;
  619.     }
  620.  
  621.     public String getPrintString() {
  622.     return printString;
  623.     }
  624.  
  625.     public void select() {
  626.     selected = true;
  627.     paused = true;
  628.     }
  629.     public void deselect() {
  630.     selected = false;
  631.     paused = false;
  632.     needRedisplay = true;
  633.     app.repaint();
  634.     }
  635.     public void paint(Graphics g, int x, int y) {
  636.     if (selected) {
  637.         g.setColor(highlightColor);
  638.     } else {
  639.         g.setColor(bgColor);
  640.     }
  641.     g.fillRect(x, y, width - 1, height);
  642.     if (valueString != null) {
  643.         switch (type) {
  644.           case Cell.VALUE:
  645.           case Cell.LABEL:
  646.         g.setColor(fgColor);
  647.         break;
  648.           case Cell.FORMULA:
  649.         g.setColor(Color.red);
  650.         break;
  651.           case Cell.URL:
  652.         g.setColor(Color.blue);
  653.         break;
  654.         }
  655.         if (transientValue){
  656.         g.drawString("" + value, x, y + (height / 2) + 5);
  657.         } else {
  658.         if (valueString.length() > 14) {
  659.             g.drawString(valueString.substring(0, 14),
  660.                  x, y + (height / 2) + 5);
  661.         } else {
  662.             g.drawString(valueString, x, y + (height / 2) + 5);
  663.         }
  664.         }
  665.     }
  666.     needRedisplay = false;
  667.     }
  668. }
  669.  
  670. class Node {
  671.     public static final int OP = 0;
  672.     public static final    int VALUE = 1;
  673.     public static final int CELL = 2;
  674.  
  675.     int        type;
  676.     Node     left;
  677.     Node     right;
  678.     int      row;
  679.     int      column;
  680.     float    value;
  681.     char    op;
  682.  
  683.     public Node() {
  684.     left = null;
  685.     right = null;
  686.     value = 0;
  687.     row = -1;
  688.     column = -1;
  689.     op = 0;
  690.     type = Node.VALUE;
  691.     }
  692.     public Node(Node n) {
  693.     left = n.left;
  694.     right = n.right;
  695.     value = n.value;
  696.     row = n.row;
  697.     column = n.column;
  698.     op = n.op;
  699.     type = n.type;
  700.     }
  701.     public void indent(int ind) {
  702.     for (int i = 0; i < ind; i++) {
  703.         System.out.print(" ");
  704.     }
  705.     }
  706.     public void print(int indentLevel) {
  707.     char l[] = new char[1];
  708.     indent(indentLevel);
  709.     System.out.println("NODE type=" + type);
  710.     indent(indentLevel);
  711.     switch (type) {
  712.       case Node.VALUE:
  713.         System.out.println(" value=" + value);
  714.         break;
  715.       case Node.CELL:
  716.         l[0] = (char)((int)'A' + column);
  717.         System.out.println(" cell=" + new String(l) + (row+1));
  718.         break;
  719.       case Node.OP:
  720.         System.out.println(" op=" + op);
  721.         left.print(indentLevel + 3);
  722.         right.print(indentLevel + 3);
  723.         break;
  724.     }
  725.     }
  726. }
  727.  
  728. class InputField {
  729.     int        maxchars = 50;
  730.     int        cursorPos = 0;
  731.     Applet    app;
  732.     String    sval;
  733.     char    buffer[];
  734.     int        nChars;
  735.     int        width;
  736.     int        height;
  737.     Color    bgColor;
  738.     Color    fgColor;
  739.  
  740.     public InputField(String initValue, Applet app, int width, int height,
  741.               Color bgColor, Color fgColor) {
  742.     this.width = width;
  743.     this.height = height;
  744.     this.bgColor = bgColor;
  745.     this.fgColor = fgColor;
  746.     this.app = app;
  747.     buffer = new char[maxchars];
  748.     nChars = 0;
  749.     if (initValue != null) {
  750.         initValue.getChars(0, initValue.length(), this.buffer, 0);
  751.         nChars = initValue.length();
  752.     }
  753.     sval = initValue;
  754.     }
  755.  
  756.     public void setText(String val) {
  757.     int i;
  758.  
  759.     for (i=0; i < maxchars; i++) {
  760.         buffer[i] = 0;
  761.     }
  762.     sval = new String(val);
  763.     if (val == null) {
  764.         sval = "";
  765.         nChars = 0;
  766.         buffer[0] = 0;
  767.     } else {
  768.         sval.getChars(0, sval.length(), buffer, 0);
  769.         nChars = val.length();
  770.         sval = new String(buffer);
  771.     }
  772.     }
  773.  
  774.     public String getValue() {
  775.     return sval;
  776.     }
  777.  
  778.     public void paint(Graphics g, int x, int y) {
  779.     g.setColor(bgColor);
  780.     g.fillRect(x, y, width, height);
  781.     if (sval != null) {
  782.         g.setColor(fgColor);
  783.         g.drawString(sval, x, y + (height / 2) + 3);
  784.     }
  785.     }
  786.     public void mouseUp(int x, int y) {
  787.     // set the edit position
  788.     }
  789.     public void keyDown(int key) {
  790.     if (nChars < maxchars) {
  791.         switch (key) {
  792.           case 8: // delete
  793.         --nChars;
  794.         if (nChars < 0) {
  795.             nChars = 0;
  796.         }
  797.         buffer[nChars] = 0;
  798.         sval = new String(new String(buffer));
  799.         break;
  800.           case 10: // return
  801.         selected();
  802.         break;
  803.           default:
  804.         buffer[nChars++] = (char)key;
  805.         sval = new String(new String(buffer));
  806.         break;
  807.         }
  808.     }
  809.     app.repaint();
  810.     }
  811.     public void selected() {
  812.     }
  813. }
  814.  
  815. class SpreadSheetInput extends InputField {
  816.     public SpreadSheetInput(String initValue,
  817.                 SpreadSheet app,
  818.                 int width,
  819.                 int height,
  820.                 Color bgColor,
  821.                 Color fgColor) {
  822.     super(initValue, app, width, height, bgColor, fgColor);
  823.     }
  824.  
  825.     public void selected() {
  826.     float f;
  827.  
  828.     switch (sval.charAt(0)) {
  829.       case 'v':
  830.         try {
  831.         f = Float.valueOf(sval.substring(1)).floatValue();
  832.         ((SpreadSheet)app).setCurrentValue(f);
  833.         } catch (NumberFormatException e) {
  834.         System.out.println("Not a float...");
  835.         }
  836.         break;
  837.       case 'l':
  838.         ((SpreadSheet)app).setCurrentValue(Cell.LABEL, sval.substring(1));
  839.         break;
  840.       case 'u':
  841.         ((SpreadSheet)app).setCurrentValue(Cell.URL, sval.substring(1));
  842.         break;
  843.       case 'f':
  844.         ((SpreadSheet)app).setCurrentValue(Cell.FORMULA, sval.substring(1));
  845.         break;
  846.     }
  847.     }
  848. }
  849.